package com.nabicht.bigblankpage.gui;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import com.nabicht.utilities.OSHandler;
import com.nabicht.utilities.DocumentManager.DefaultDocumentManager;
import com.nabicht.utilities.DocumentManager.ManagedDocument;
import com.nabicht.utilities.RecentDocuments.RecentDocuments;
import com.nabicht.utilities.keylistener.GeneratedKeyListener;

public class BigBlankPage implements ActionListener {
	
	private final static int DOCUMENT_INSET = 20;
	
	private DefaultDocumentManager documentManager = new DefaultDocumentManager("bbp", "temp", "txt");
	private GeneratedKeyListener keyListener;
	
	private boolean fullScreenFlag = false;
	
	private JFileChooser fc = new JFileChooser();
	private BBPFrame fullScreenFrame = null; 
	private ProgramMenu menuPanel = null;
	private RecentDocuments recentDocuments = new RecentDocuments(new File("RecentDocuments.xml"));
	
	public BigBlankPage() {
		
		InputStream is = getClass().getClassLoader().getResourceAsStream("resources/KeyListenerConfig.xml");
		keyListener = new GeneratedKeyListener(is);
		keyListener.addActionListener(this);
		
		File file = new File("tempfile");  //TODO make this open the last open file and if there was no last open file, create a new one
		setActiveDocument(new BBPDocument(file, documentManager));	
		
		setFullScreen(false);	
		
		//set up fullscreen frame
		fullScreenFrame = new BBPFrame(null);
		fullScreenFrame.setLocation(0, 0);
		fullScreenFrame.setUndecorated(true);
		fullScreenFrame.setResizable(false);
		fullScreenFrame.setVisible(false);
		
		Runtime.getRuntime().addShutdownHook(new Thread() {
	        // This method is called during shutdown
	        public void run() {
	            ((BBPDocument)documentManager.getActiveDocument()).save();
	        }
	    });
	}
	
	private void setActiveDocument(BBPDocument document) {
		BBPDocument prevActiveDocument = getActiveDocument();
		documentManager.setActiveDocument(document);
		if (this.fullScreenFlag == false) {
			getActiveDocument().getFrame().pack();
		}
		if (prevActiveDocument != null) {
			prevActiveDocument.removeKeyListener(keyListener);
			prevActiveDocument.save();
		}
		BBPDocument activeDocument = getActiveDocument();
		activeDocument.addKeyListener(keyListener);
		if (fullScreenFlag) {
			fullScreenFrame.setDocument(activeDocument);
			fullScreenFrame.setVisible(true);
        	activeDocument.getPanel().requestFocus();
		} else {
			activeDocument.getFrame().setEnabled(true);
        	activeDocument.getPanel().setEnabled(true);
        	activeDocument.getFrame().setVisible(true);
        	activeDocument.getPanel().requestFocus();
		}
	}
	
	private BBPDocument getActiveDocument() {
		return (BBPDocument)(documentManager.getActiveDocument());
	}
	
	public void actionPerformed(ActionEvent ae) {
		String cmd = ae.getActionCommand();
		if (cmd.equals("toggle fullscreen")) {
			setFullScreen(!fullScreenFlag);
		} else if (cmd.equals("save file") || cmd.equals(ProgramMenu.SAVE_AC)) {
			getActiveDocument().save();
		} else if (cmd.equals("save file as") || cmd.equals(ProgramMenu.SAVE_AS_AC)) {
			saveFileAs();
		} else if (cmd.equals("open file") || cmd.equals(ProgramMenu.OPEN_AC)) {
			saveActiveDocument();
			chooseAndOpenFile();
		} else if (cmd.equals("show menu")) {
			showMenu();
		} else if (cmd.equals("close current")) {
			BBPDocument activeDocument = getActiveDocument();
			if (activeDocument == null) return;
			String path = activeDocument.getFile().getAbsolutePath();
			closeActiveDocument();
			recentDocuments.addRecentDocument(path);
		} else if (cmd.equals(ProgramMenu.MENU_CLOSED_AC)) {
			closeMenu();
		} else if (cmd.equals("print document")) {
			System.out.println("PRINT");
			BBPDocument activeDocument = getActiveDocument();
			if (activeDocument == null) return;
			PrinterJob job = PrinterJob.getPrinterJob();
			job.setPrintable(activeDocument);
			boolean doPrint = job.printDialog();
			if (doPrint) {
				try {
					job.print();
				} catch (PrinterException e) {
					e.printStackTrace();
				}
			}
			//TODO print 
		} else if (cmd.equals("new document")) {
			saveActiveDocument();
			File file = new File(documentManager.generateNewFileName());
			try {
				file.createNewFile();
			} catch (IOException ioe) {
				System.err.println("Problem creating file: " + file.getName());
				ioe.printStackTrace();
				return;
				//TODO something better than just printing the err here
			}
			BBPDocument document = new BBPDocument(file, documentManager);
			setDefaultLocation(document, documentManager);
			setActiveDocument(document);
		}
		
	}
	
	private void saveActiveDocument() {
		BBPDocument activeDocument = getActiveDocument();
		if (activeDocument == null) return;
		
		//TODO if active document has never been saved before then do the "save as"
		activeDocument.save();
	}
	
	
	private void closeActiveDocument() {
		BBPDocument activeDocument = getActiveDocument();
		if (activeDocument == null) return;
		
		//TODO need to get the program to not exit after closing the last window
		activeDocument.save();
		activeDocument.getFrame().dispose();
	}
	
	private void closeMenu() {
		if (menuPanel == null) return;
		BBPDocument activeDocument = getActiveDocument();
		if (activeDocument == null) return;
		final JPanel glass = (JPanel)(fullScreenFlag ? fullScreenFrame.getGlassPane() : activeDocument.getFrame().getGlassPane());
		glass.removeAll();
		glass.setVisible(false);
		keyListener.setEnabled(true);
		activeDocument.getPanel().setEnabled(true);
		activeDocument.getPanel().requestFocus();
	}
	
	private void showMenu() {
		BBPDocument activeDocument = getActiveDocument();
		if (activeDocument != null) {
			activeDocument.getPanel().setEnabled(false);
		}
		keyListener.setEnabled(false);
		final JPanel glass = fullScreenFlag ? (JPanel)fullScreenFrame.getGlassPane() : (JPanel)activeDocument.getFrame().getGlassPane();
		menuPanel = ProgramMenu.getMenu();
		menuPanel.addActionListener(this);
		glass.add(menuPanel);
		glass.setVisible(true);
		menuPanel.requestFocus();
	}
	
	private void chooseAndOpenFile() {
		BBPDocument activeDocument = getActiveDocument();
		int returnVal = fc.showOpenDialog(activeDocument.getFrame());
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            setActiveDocument(new BBPDocument(file, documentManager));
            setFullScreen(fullScreenFlag);
        }
	}
	
	private void saveFileAs() {
		BBPDocument activeDocument = getActiveDocument();
		if (activeDocument == null) return;
		String path = activeDocument.getFile().getAbsolutePath();
		if (documentManager.isGeneratedFileName(activeDocument.getFile().getName())) {
			path = null;
		}
		JFrame frame = fullScreenFlag ? fullScreenFrame : activeDocument.getFrame();
		int returnVal = fc.showSaveDialog(frame);
		//TODO try the solution where I extend JInternalFrame, add the filechooser to that and then manage jinternalframe visibility (google for soultion0
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            if (file.exists()) {
            	String message = "Are you sure you want to overwrite " + file.getName() + "?";
            	int result = JOptionPane.showConfirmDialog(activeDocument.getFrame(), message, "alert", JOptionPane.OK_CANCEL_OPTION);
            	if (result == JOptionPane.CANCEL_OPTION) {
            		return;
            	}
            } else {
            	try {
            		file.createNewFile();
            	} catch (IOException ioe) {
            		ioe.printStackTrace();
            		//TODO log this if we have a log
            		//TODO popup dialog showing that something is wrong
            		return;
            	}
            }
            activeDocument.setFile(file, documentManager);
            activeDocument.save();
            if (path != null) {
            	recentDocuments.addRecentDocument(path);
            }
        }
	}
	
	private void nonFullScreen() {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	if (fullScreenFrame != null) {
            		fullScreenFrame.setEnabled(false);
            		fullScreenFrame.setVisible(false);
            		fullScreenFrame.setDocument(null);
            	}
            	BBPDocument activeDocument = getActiveDocument();
            	activeDocument.getFrame().setDocument(activeDocument);
            	activeDocument.getFrame().setEnabled(true);
            	activeDocument.getPanel().setEnabled(true);
            	activeDocument.getFrame().setVisible(true);
            	activeDocument.getPanel().requestFocus();
            	activeDocument.getPanel().ensureCaretVisibility();
            }
        });
	}
	
	
	private void fullScreen() {
		//setFrameData();
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
            	BBPDocument activeDocument = getActiveDocument();
            	if (activeDocument == null) return;
            	activeDocument.getFrame().setVisible(false);
            	fullScreenFrame.setDocumentName(activeDocument.getFile().getName());
            	fullScreenFrame.setDocument(activeDocument);
            	fullScreenFrame.setSize(getScreenSize());
            	fullScreenFrame.toFront();
    			fullScreenFrame.setVisible(true);
    			fullScreenFrame.setEnabled(true);
    			activeDocument.getPanel().requestFocus();
            }
        });
	}
	
	public void setFullScreen(boolean fullScreen) {
		if (!fullScreen) {
			this.fullScreenFlag = fullScreen;
			nonFullScreen();
		} else {
			this.fullScreenFlag = fullScreen;
			fullScreen();
		}
	}
	
	//TODO unit test this. I want to make sure this works
	private static void setDefaultLocation(BBPDocument document, DefaultDocumentManager docManager) {
		Dimension screenSize = getScreenSize();
		BBPFrame frame = document.getFrame();
		Point docLocation = new Point(DOCUMENT_INSET, DOCUMENT_INSET);
		
		/*if the size of frame is bigger than size of screen then set location and size and move on */
		boolean tooBig = false;
		int width = frame.getWidth();
		int height = frame.getHeight();
		if (frame.getWidth() > screenSize.width) {
			width = screenSize.width - (DOCUMENT_INSET * 2);
			tooBig = true;
		}
		if (frame.getHeight() > screenSize.height) {
			height = screenSize.height - (DOCUMENT_INSET * 2);
			tooBig = true;
		}
		
		if (tooBig) {
			Dimension size = new Dimension(width, height);
			frame.setSize(size);
			frame.setLocation(docLocation);
			return;
		}
		 
		Point endResult = new Point(DOCUMENT_INSET, DOCUMENT_INSET);
		boolean changed = true;
		while(changed) {
			changed = false;
			for (ManagedDocument doc : docManager.getDocumentsArray()) {
				Point location = ((BBPDocument)doc).getFrame().getLocation();
				if (equivalentLocation(docLocation.x, location.x, DOCUMENT_INSET) || 
						equivalentLocation(docLocation.y, location.y, DOCUMENT_INSET)) 
				{
					docLocation = new Point(location.x + DOCUMENT_INSET, location.y + DOCUMENT_INSET);
					changed = true;
				}
			}
			
			if (changed == true && docLocation == endResult) {
				changed = false;
			}
			
			/*If the new location + the size of the frame > screen allows, then break out of loop*/
			int horizontalOutterBound = docLocation.x + frame.getWidth();
			int verticalOutterBound = docLocation.y + frame.getHeight();
			if (horizontalOutterBound > screenSize.width || verticalOutterBound > screenSize.height) {
				changed = false;
				docLocation = new Point(DOCUMENT_INSET, DOCUMENT_INSET);
			}
			
			endResult = new Point(docLocation.x, docLocation.y);
		}
		document.getFrame().setLocation(docLocation);
	}
	
	private static boolean equivalentLocation(int a, int b, int delta) {
		if ((a > (b - delta)) && ( a < (b + delta))) return true;
		return false;
	}
	
	private static Dimension getScreenSize() {
		return java.awt.Toolkit.getDefaultToolkit().getScreenSize();
	}
	
	
	private static void setupOSSpecific() {
		if (OSHandler.isMac()) {
			System.setProperty("com.apple.mrj.application.apple.menu.about.name", "BigBlankPage");
		}
	}
	
	public static void main(String[] args) {
		setupOSSpecific();
		new BigBlankPage();
	}

}
